package com.qfmy.common.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.jetbrains.annotations.NotNull;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

/**
 * @author 清风明月
 * @Package com.qfmy.common.utils
 * @date 2025/9/11
 * @description 二维码工具类
 */
@SuppressWarnings("all")
public class QrCodeUtils {
    private static final Logger log = Logger.getLogger(QrCodeUtils.class.getName());
    private static final int DEFAULT_SIZE = 400; // 二维码默认尺寸
    private static final double LOGO_SCALE_RATIO = 0.25; // 头像占二维码比例
    private static final int HTTP_TIMEOUT = 5000; // HTTP请求超时时间(毫秒)
    private static final String DEFAULT_AVATAR = "classpath:avatar/default.jpg"; // 默认头像

    /**
     * 生成带头像的二维码（自动识别头像来源）
     * @param content 二维码内容（URL/文本）
     * @param logoSource 头像来源（HTTP URL/本地路径/classpath:资源路径）
     * @param outputPath 输出路径（null则返回BufferedImage）
     */
    public static BufferedImage generateQrCodeWithLogo(
            String content, String logoSource, String outputPath) throws WriterException, IOException {
        return generateQrCodeWithLogo(content, logoSource, outputPath, DEFAULT_SIZE, DEFAULT_SIZE);
    }

    /**
     * 生成带头像的二维码（指定尺寸）
     */
    public static BufferedImage generateQrCodeWithLogo(
            String content, String logoSource, String outputPath, int width, int height)
            throws WriterException, IOException {
        // 1. 生成基础二维码
        BitMatrix bitMatrix = createQrCodeBitMatrix(content, width, height);
        BufferedImage qrCodeImage = MatrixToImageWriter.toBufferedImage(bitMatrix,
                new MatrixToImageConfig(0xFF000000, 0xFFFFFFFF)); // 黑码白背景

        // 2. 读取头像（支持HTTP/本地/resources）
        BufferedImage logoImage = getLogoImage(logoSource);

        // 3. 合成二维码和头像
        BufferedImage resultImage = mergeQrCodeAndLogo(qrCodeImage, logoImage);

        // 4. 写入文件（可选）
        if (outputPath != null) {
            File outputFile = new File(outputPath);
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }
            ImageIO.write(resultImage, "png", outputFile);
        }

        return resultImage;
    }

    /**
     * 自动识别头像来源并获取图像
     */
    private static BufferedImage getLogoImage(String logoSource) throws IOException {
        if (logoSource == null || logoSource.trim().isEmpty()) {
            log.warning("头像来源为空，使用默认头像");
            return getDefaultLogo();
        }

        // 处理HTTP/HTTPS URL
        if (logoSource.startsWith("http://") || logoSource.startsWith("https://")) {
            try {
                return getLogoFromHttpUrl(logoSource);
            } catch (Exception e) {
                log.warning("HTTP头像读取失败：" + e.getMessage() + "，使用默认头像");
                return getDefaultLogo();
            }
        }

        // 处理classpath资源
        if (logoSource.startsWith("classpath:")) {
            try {
                String resourcePath = logoSource.replace("classpath:", "").trim();
                return getLogoFromResources(resourcePath);
            } catch (Exception e) {
                log.warning("Resources头像读取失败：" + e.getMessage() + "，使用默认头像");
                return getDefaultLogo();
            }
        }

        // 处理本地文件
        try {
            File logoFile = new File(logoSource);
            if (!logoFile.exists()) {
                throw new FileNotFoundException("本地文件不存在：" + logoSource);
            }
            return ImageIO.read(logoFile);
        } catch (Exception e) {
            log.warning("本地头像读取失败：" + e.getMessage() + "，使用默认头像");
            return getDefaultLogo();
        }
    }

    /**
     * 从HTTP URL读取头像
     */
    private static BufferedImage getLogoFromHttpUrl(String urlStr) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(HTTP_TIMEOUT);
        conn.setReadTimeout(HTTP_TIMEOUT);
        conn.setRequestProperty("User-Agent", "Mozilla/5.0");

        if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
            throw new IOException("HTTP响应异常：" + conn.getResponseCode());
        }

        try (InputStream inputStream = conn.getInputStream()) {
            return ImageIO.read(inputStream);
        } finally {
            conn.disconnect();
        }
    }

    /**
     * 从resources读取头像
     */
    private static BufferedImage getLogoFromResources(String resourcePath) throws IOException {
        InputStream inputStream = QrCodeUtils.class.getClassLoader().getResourceAsStream(resourcePath);
        if (inputStream == null) {
            throw new IOException("资源不存在：" + resourcePath);
        }
        try (inputStream) {
            return ImageIO.read(inputStream);
        }
    }

    /**
     * 获取默认头像（兜底）
     */
    private static BufferedImage getDefaultLogo() throws IOException {
        return getLogoFromResources(DEFAULT_AVATAR.replace("classpath:", ""));
    }

    /**
     * 生成二维码矩阵
     */
    private static BitMatrix createQrCodeBitMatrix(String content, int width, int height) throws WriterException {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 支持中文
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 高容错
        hints.put(EncodeHintType.MARGIN, 1); // 边距
        return new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    }

    /**
     * 合成二维码和头像（核心方法，修复资源释放语法）
     */
    private static BufferedImage mergeQrCodeAndLogo(BufferedImage qrCode, BufferedImage logo) {
        int qrWidth = qrCode.getWidth();
        int qrHeight = qrCode.getHeight();

        // 计算头像尺寸并缩放
        int logoWidth = (int) (qrWidth * LOGO_SCALE_RATIO);
        int logoHeight = (int) (qrHeight * LOGO_SCALE_RATIO);
        BufferedImage scaledLogo = new BufferedImage(logoWidth, logoHeight, BufferedImage.TYPE_INT_ARGB);

        // 缩放头像（修复try-with-resources错误）
        Graphics2D g = scaledLogo.createGraphics();
        try {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.drawImage(logo, 0, 0, logoWidth, logoHeight, null);
        } finally {
            g.dispose(); // 手动释放资源
        }

        // 合成最终图像
        BufferedImage result = new BufferedImage(qrWidth, qrHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = result.createGraphics();
        try {
            // 绘制二维码
            g2.drawImage(qrCode, 0, 0, null);
            // 计算头像居中位置
            int x = (qrWidth - logoWidth) / 2;
            int y = (qrHeight - logoHeight) / 2;
            // 绘制头像
            g2.drawImage(scaledLogo, x, y, null);
            // 绘制白色边框
            g2.setStroke(new BasicStroke(3));
            g2.setColor(Color.WHITE);
            g2.drawRect(x, y, logoWidth, logoHeight);
        } finally {
            g2.dispose(); // 手动释放资源
        }

        return result;
    }

    /**
     * BufferedImage转字节数组
     */
    @NotNull
    public static byte[] bufferedImageToBytes(BufferedImage image) throws IOException {
        return bufferedImageToBytes(image, "png");
    }

    /**
     * BufferedImage转字节数组
     * @param image
     * @param format
     * @return
     * @throws IOException
     */
    @NotNull
    public static byte[] bufferedImageToBytes(BufferedImage image, String format) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            ImageIO.write(image, format, outputStream);
            return outputStream.toByteArray();
        }
    }

    /**
     * BufferedImage转Base64字符串
     */
    @NotNull
    public static String bufferedImageToBase64(BufferedImage image) throws IOException {
        return bufferedImageToBase64(image, "png");
    }

    /**
     * BufferedImage转Base64字符串
     * @param image
     * @param format
     * @return
     * @throws IOException
     */
    @NotNull
    public static String bufferedImageToBase64(BufferedImage image, String format) throws IOException {
        byte[] bytes = bufferedImageToBytes(image, format);
        return "data:image/" + format + ";base64," + java.util.Base64.getEncoder().encodeToString(bytes);
    }

}